unit UmainForm;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Forms, Controls, IniFiles,
  Grids,

  // Self-made units
  UGameSys, Upixeng, UCommon, UGraph, UResMan, UMover,

  // other units
  Pathfind;

//------------------------------------------------------------------------------

type
  TMainForm = class(TForm)
    procedure FormDestroy(Sender: TObject);
    procedure FormMouseWheel(Sender: TObject; Shift: TShiftState;
      WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
  published
    SgMap: TStringGrid;
    procedure FormKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure FormPaint(Sender: TObject);
    procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; x, y: Integer);
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; x,
      y: Integer);
    procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; x, y: Integer);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure SgMapDrawCell(Sender: TObject; ACol, ARow: Integer;
      Rect: TRect; State: TGridDrawState);
    procedure SgMapMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; x, y: Integer);
    procedure LVarmyMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; x, y: Integer);
    procedure FormResize(Sender: TObject);
    procedure SgMapTopLeftChanged(Sender: TObject);
    procedure BTeleportClick(Sender: TObject);
  private
    DC: HDC;

    FPath: TPath;
    FormState: NFormState; // indicates current FormState
    FDlg: Tsimpledlg;
    Flst: TGameIntfLst;
    Angel: TGameIntfAnim;
    bkg: TGameintfbkgdSimple; //  MapForm
    Bstart: TGameintfBtn; //
    Bback: TGameintfBtn; //
    LCMaps: TGameintflst; //
    LMapinfo: TGameintflst; //-----------

    Bnew: TGameintfbtn; // menuForm
    bexit: TGameintfbtn; //
    Ltitle: TGameintflst; //
    Bresume: TGameintfbtn; //----------
    procedure SetDlg(const Value: Tsimpledlg);
    procedure SetPath(P: TPath);
    procedure Makemenu();
    procedure MakeMapForm();
    procedure MakeForm(Mapind: Word);
    procedure LoadResources();
    procedure SetDiRectories();
  public
    // all of following are Pixeng interface Parts, it owns and frees them
    function MovingCost(x, y, DiRection: smallint): smallint;
    procedure camerafollow(aCell: TFieldCell);
    procedure DoQuit(Sender: TObject);
    procedure drawCell(aCell: TFieldCell);
    procedure drawMap;
    procedure DrawPath(PathVisible: Boolean);
    procedure FieldCellChanged(Sender: TObject);
    procedure FormGameTimer(Sender: TObject);
    procedure frommenuleaverequest(dr: NdlgResult);
    procedure fromquitrequest(dr: NdlgResult);
    procedure fromrestartrequest(dr: NdlgResult);
    procedure keyback(Sender: TObject);
    procedure keyBegin(Sender: TObject);
    procedure keystart(Sender: TObject);
    procedure LeavetoMenu();
    procedure preclose(Sender: TObject);
    procedure PreLeave(Sender: TObject);
    procedure Redraw;
    procedure RedrawGrid(var AMask: tMask);
    procedure scaler;
    procedure start();
    procedure TitleGlow(Sender: TObject);
    procedure Updatelvarmy(aCell: TFieldCell);
    property Path: TPath read FPath write SetPath;
    property Dlg: Tsimpledlg read FDlg write SetDlg;
    // controls' handlers
    procedure GresumeGame(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; x, y: Integer);
    procedure BstartClick(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; x, y: Integer);
    procedure BbackClick(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; x, y: Integer);
    procedure LCMapsChanged(Sender: TObject);
    procedure GnewGame(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; x, y: Integer);
    procedure Gquit(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; x, y: Integer);
    procedure BmenuClick(Sender: TObject);
    procedure AngelLeft(Sender: TObject);
    procedure AngelRight(Sender: TObject);
    procedure AngelUp(Sender: TObject);
    procedure AngelDown(Sender: TObject);
    procedure PreMake;
    procedure PostMake;
  end;

  //------------------------------------------------------------------------------

const
  fovRowcnt = 5;
  fovColcnt = 3;
  Colnum = 3;
  Colhdrsizes: array[1..Colnum] of Byte = (99, 25, 40);
  Colhdrs: array[1..Colnum] of string = ('Party', '#', 'Qnt');
  //------------------------------------------------------------------------------

var
  MainForm: TMainForm;

implementation

uses uSound;

{$R *.dfm}

procedure TMainForm.FormCreate(Sender: TObject);
var
  Inif: tmemIniFile;
  //  i: byte;
begin
  Application.Title := Apptitle;
  Caption := Apptitle + ' ' + Appver;
  Inif := tmemIniFile.Create(AppPath + optionsIni);
  if Inif <> nil then
  begin
    // all Ini handling, i.e. options
  end;
  FreeAndNil(Inif);
  DoubleBuffered := True;
  KeyPreview := True;
  BorderStyle := bsNone;
  SgMap.Visible := False;
  SetdiRectories();
  CreateGame(AppPath);
  Loadresources();
  Makemenu; // needed for position, maybe later refactored to Form-config-Loading

  //  ClientHeight := ResMan.GraphicN[giMenuform].Bmp.Height;
  //  ClientWidth := ResMan.GraphicN[giMenuform].Bmp.Width;
  //  Position := poScreenCenter;
  //  for i := 1 to Colnum do
  //  begin
  //    LVarmy.Columns.Add;
  //    LVarmy.Column[i - 1].caption := Colhdrs[i];
  //    LVarmy.Column[i - 1].Width := Colhdrsizes[i];

  //    LVarmy.Column[i - 1].minWidth := Colhdrsizes[i];
  //    LVarmy.Column[i - 1].maxWidth := Colhdrsizes[i];
      // OMFG not working allowresize from TcustomHeaderSection
  //  end;

end;

//------------------------------------------------------------------------------

procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  preclose(nil);
  action := canone;

  //  if action = cahide then
  //  begin
  //    DestroyGame;
  //    Application.terminate;
  //  end;
end;

//------------------------------------------------------------------------------

procedure TMainForm.drawCell(aCell: TFieldCell);
var
  Rect, rec: tRect;
  Bmp: TBmp;

begin
  Bmp := TBmp.Create;
  Bmptrans(Bmp);

  with aCell, sgMap.Canvas do
  begin
    if not ((xCord in [sgMap.LeftCol..sgMap.LeftCol + sgMap.VisibleColCount])
      and (yCord in [sgMap.TopRow..sgMap.TopRow + sgMap.VisibleRowCount])) then
      Exit;
    Rect := sgMap.CellRect(xCord, yCord);
    rec := Rect;
    if Assigned(ResMan.GraphicN[terassoc[tertype]].Imglst
      {terBmps[ord(tertype), tertex]}) then
    begin
      ResMan.GraphicN[terassoc[tertype]].Imglst.GetBitmap(tertex, Bmp);
      {terBmps[ord(tertype), tertex]}
      Flip(Bmp, mirror[0], mirror[1]);
      Draw(Rect.Left, Rect.Top, Bmp);
    end
    else
    begin
      rec := Rect;
      brush.Color := terColar[Ord(tertype)];
      fillRect(rec);
    end;
    if Obj <> nil then
    begin
      rec := Rect;
      inflateRect(rec, -5, -5);
      brush.Color := clGray;
      fillRect(rec);
      Textout(rec.Left, rec.Top, IntToStr(Obj.subtype));
    end;
    if army <> nil then
    begin
      rec := Rect;
      inflateRect(rec, -7, -7);
      if army.Parties.Count > 0 then
        case army.Parties.Items[army.Parties.Count - 1].Force of
          //fnone : brush.Color := clwhite;
          fplayer: brush.Color := clblue;
          fally: brush.Color := cllime;
          fenemy: brush.Color := clred;
        end;
      ellipse(rec);
    end;
    if onPath = 1 then
    begin
      rec := Rect;
      brush.Color := clblack;
      inflateRect(rec, -13, -13);
      FrameRect(rec);
    end;
  end;
  Bmp.free;
end;

//------------------------------------------------------------------------------

procedure TMainForm.SgMapDrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
begin
  if Game.MapLoaded and Game.Field.CheckInMap(ARow, aCol) then
    if Assigned(Game.Field[aRow, aCol]) then
      drawCell(Game.Field[aRow, aCol]);
end;

//------------------------------------------------------------------------------

procedure TmainForm.RedrawGrid(var AMask: tMask);
var
  i, j: Byte;
begin
  for i := Game.Field.ViewZone.Top to Game.Field.ViewZone.Bottom do
    for j := Game.Field.ViewZone.Left to Game.Field.ViewZone.Right do
      if AMask.Cells[i - Game.Field.ViewZone.Top, j - Game.Field.ViewZone.Left]
        then
        drawCell(Game.Field[i, j]);
end;

//------------------------------------------------------------------------------

procedure TMainForm.BmenuClick(Sender: TObject);
begin
  PreLeave(nil);
end;

procedure TMainForm.BstartClick(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; x, y: Integer);
begin
  if LcMaps.curSel in [0..Game.MapMgr.Mapqnt - 1] then
    Game.MapMgr.curmap := LcMaps.curSel
  else
    Exit;
  //  Hide;
    //mainForm.drawMap;
  //  mainForm.show;
  //  mainForm.Enabled := true;
    //FormState := fsMenu;
  MakeForm(Game.MapMgr.curmap);
end;

//------------------------------------------------------------------------------
// back-btn handler (in fsMapForm)

procedure TMainForm.BbackClick(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; x, y: Integer);
begin
  Makemenu;
  //FormState := fsMenu;
  //Invalidate;
end;

//------------------------------------------------------------------------------
// Maps-list Selection-changed handler

procedure TMainForm.LCMapsChanged(Sender: TObject);
begin
  if LCMaps.curSel in [0..Game.MapMgr.Mapqnt - 1] then
  begin
    LMapinfo.Clear;
    LMapinfo.AddMultiLineText(Game.MapMgr.Mapar[LCMaps.curSel].Descr);
  end;
end;

//------------------------------------------------------------------------------
// resume-btn handler (in fsMenu, when Game is paused) maybe transfered to MainForm

procedure TMainForm.GresumeGame;
begin
  if Game.MapLoaded then
  begin
    //hide;
//    mainForm.Enabled := true;
//    MainForm.Visible := True;
    MakeForm(Game.MapMgr.curmap);
  end;
end;

//------------------------------------------------------------------------------

procedure TMainForm.drawMap;
begin
  sgMap.ColCount := Game.Field.Width;
  sgMap.RowCount := Game.Field.Height;
  scaler;
end;

//------------------------------------------------------------------------------

procedure TMainForm.SgMapMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; x, y: Integer);
var
  c, r: Integer;
  //  tCell: TFieldCell;
begin
  with Game do
  begin
    SGMap.MousetoCell(x, y, c, r);
    if not ((c in [0..Field.Width - 1]) and (r in [0..Field.Height - 1])) or not
      MapLoaded then
      Exit;
    if (Field[r, c].army <> nil) and (Field[r, c].army.Parties.Count <> 0) and
      (button = mbLeft) then
    begin
      Updatelvarmy(Field[r, c]);
      if ((CurParty = nil) or (Field[r, c].army.Parties.Count = 1))
        and (Field[r, c].army.Parties.Items[0].Force = fplayer) then
      begin
        CurParty := Field[r, c].army.Parties.Items[0];
        Path := CurParty.Path; // show Path of choosen Party on Map
        // TODO show Warriors list of CurParty
        if CurParty <> nil then
          camerafollow(CurParty.Cell);
      end;
    end;

    if (CurParty <> nil) and (button = mbRight) then
    begin
      //      tCell := CurParty.Cell;
      if CurParty.DestCell = Field[r, c] then
        doTick // CurParty (as memory Obj) here "changes"
      else
      begin
        CurParty.DestCell := Field[r, c];
        x := CurParty.Cell.xCord;
        y := CurParty.Cell.yCord;
        CurParty.Path := findPath(Field.Width, Field.Height, x, y, C, R,
          movingcost);
        Path := CurParty.Path;
        CurParty.CurStep := 0;
        CurParty.Time := 0;
      end;
      UpdateLVarmy(CurParty.Cell);
      camerafollow(CurParty.Cell);
    end;
  end;
end;

//------------------------------------------------------------------------------

procedure TMainForm.SetPath(P: TPath);
begin
  DrawPath(False); // erasing old Path
  FPath := P;
  DrawPath(True); // drawing new Path
end;

procedure TMainForm.DrawPath(PathVisible: Boolean);
var
  i {, d, px, py, pox,poy }: Byte;
  //pts : word;
begin
  if (FPath <> nil) {//  there is a Path} then
    for i := 1 to High(FPath) do //  iterate all Path elements
    begin
      Game.Field[fPath[i].y, fPath[i].x].onPath := Integer(PathVisible);
      drawCell(Game.Field[fPath[i].y, fPath[i].x]);
    end;
end;

//------------------------------------------------------------------------------

function TMainForm.MovingCost(x, y, DiRection: smallint): smallint;
begin
  case Game.Field[y, x].tertype of
    ttdirt: Result := 10;
    ttsand: Result := 15;
    ttGrass: Result := 10;
    ttsnow: Result := 15;
    ttswamp: Result := 17;
    ttrough: Result := 12;
    ttcave: Result := 10;
    ttlava: Result := 10;
    ttwater: Result := 10;
  else
    Result := -1;
  end;
  if (Result > 0) and odd(DiRection) then // if diagonal diRection
    inc(Result, Result shr 1); // multiply by almost 1.5
end;

//------------------------------------------------------------------------------

procedure TMainForm.Updatelvarmy(aCell: TFieldCell);
//var
//  i: byte;
begin
  {with LVarmy, aCell.army do
  begin
    LVarmy.Clear;
    for i := 0 to Parties.Count - 1 do
    begin
      AddItem(Getenumname(typeinfo(Nforce), ord(Parties.Items[i].force)),
        Parties.Items[i]);
      Items[i].SubItems.Clear;
      Items[i].subItems.Add(inttostr(Parties.Items[i].index));
      if Parties.Items[i].Warriors <> nil then
        Items[i].subItems.Add(inttostr(Parties.Items[i].Warriors.Count));
    end;
  end;    }
end;

//------------------------------------------------------------------------------

procedure TMainForm.LVarmyMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; x, y: Integer);
begin
  {if (Sender as tlistView).Itemindex <> -1 then
  begin
    Game.CurParty := TParty((Sender as tlistView).Items[(Sender as
        tlistView).Itemindex].data);
    Path := Game.CurParty.Path;
    // show list of Warriors
  end;}
end;

//------------------------------------------------------------------------------

procedure TMainForm.FormResize(Sender: TObject);
begin
  //WindowState := wsMaximized;
  scaler;
end;

//------------------------------------------------------------------------------

procedure TMainForm.scaler;
begin
  sgMap.DefaultColWidth := Cellsize;
  sgMap.DefaultRowHeight := Cellsize;
  if SGMap.Width <> clientWidth - 200 then
    SGMap.Width := clientWidth - 200;
  if SGMap.Height <> clientHeight then
    SGMap.Height := clientHeight;
  SGMap.ClientWidth := SGMap.VisibleColCount * SGMap.defaultColWidth;
  SGMap.ClientHeight := SGMap.VisibleRowCount * SGMap.defaultRowHeight;
  //sgMapTopLeftchanged(nil);
end;

//------------------------------------------------------------------------------

procedure TMainForm.BTeleportClick(Sender: TObject);
//var ty,tx : word;
begin
  if Assigned(Game.CurParty) then
    with Game.CurParty do
      if (Cell.Obj <> nil) and (Cell.Obj.oType = otportal) then
      begin
        //tCell := Cell ;
        Game.CurParty.Teleport; // Teleport 'em ! CurParty changed
        //drawCell(tCell);   // draw old Cell
        //drawCell(Game.CurParty.Cell);  // draw new Cell
        camerafollow(Game.CurParty.Cell);
        Redraw;
      end;
end;

//------------------------------------------------------------------------------

procedure TMainForm.camerafollow(aCell: TFieldCell);
var
  fTopRow, fLeftCol, fbotRow, fRightCol, hl, vl: Integer;
begin
  with SGMap do
  begin
    fTopRow := TopRow + ((TopRow + VisibleRowCount) div fovRowcnt) * (fovRowcnt
      div 2);
    fbotRow := fTopRow + (TopRow + VisibleRowCount) div fovRowcnt;
    fLeftCol := LeftCol + ((LeftCol + VisibleColCount) div fovColcnt) *
      (fovColcnt div 2);
    fRightCol := fLeftCol + (fLeftCol + VisibleColCount) div fovColcnt;
    {fbotRow := TopRow + VisibleRowCount;
    fRightCol := LeftCol + VisibleColCount ;}
    if not (aCell.xCord in [fLeftCol..fRightCol]) then
    begin
      vl := aCell.xCord - VisibleColCount div 2;
      if vl < 0 then
        LeftCol := 0
      else if vl + VisibleColCount > ColCount - 1 then
        LeftCol := ColCount - VisibleColCount
      else
        LeftCol := vl;
    end;
    if not (aCell.yCord in [fTopRow..fbotRow]) then
    begin
      hl := aCell.yCord - VisibleRowCount div 2;
      if hl < 0 then
        TopRow := 0
      else if hl + VisibleRowCount > RowCount - 1 then
        TopRow := RowCount - VisibleRowCount
      else
        TopRow := hl;
    end;
  end; // with
end;

//------------------------------------------------------------------------------

procedure TMainForm.SgMapTopLeftChanged(Sender: TObject);
begin
  Game.Field.LeftCol := sgMap.LeftCol;
  Game.Field.TopRow := sgMap.TopRow;
  Game.Field.VisCol := sgMap.VisibleColCount;
  Game.Field.VisRow := sgMap.VisibleRowCount;
  Game.ResetGridMask;
  Redraw;
end;

procedure TMainForm.Redraw;
begin
  RedrawGrid(Game.GridMask);
end;

procedure TMainForm.GnewGame(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; x, y: Integer);
begin
  if Game.MapLoaded then // show question whether to kill current Game
    dlg := Game.CreateDlg(tyesnodlg, lsnewGame, fromrestartrequest)
  else if Game.MapMgr.LoadMaphdrs = 0 then // no Maps in Maps dir - show warning
    dlg := Game.CreateDlg(TOkbtndlg, lsnoMaps, nil)
  else
    start; // all fine, show MapForm
end;

procedure TMainForm.Makemenu;
var
  aBmp: TBmp;
  ClWd, ClHg: Integer;

begin
  PreMake;
  FormState := fsMenu;

  aBmp := ResMan.GraphicN[giMenuform].Bmp;
  clhg := Min(aBmp.Height, screen.DeskTopHeight); // Set Form size
  clwd := Min(aBmp.Width, screen.DeskTopWidth); // later maybe done
  // by Form-config Loading
  ClientWidth := clwd;
  ClientHeight := clhg;

  Game.GamePix.Reset(ClHg, ClWd);

  bkg := Game.GamePix.Addbkgd(0, 0, ClHg, ClWd, aBmp, jmNone,
    TGameIntfBkgdSimple) as TGameIntfBkgdSimple;
  Game.Input.RegKey(bkg, ord('Q'), [ssCtrl, ssAlt], Doquit);

  Bnew := Game.GamePix.Addbtn(140, 350, ResMan.GraphicN[ginewGame]);
  with Bnew do
  begin
    GrafDefinesSize; // this shows we don't Set sizes, it reads them from Graphics
    ImgObj.onMouse := GnewGame; // Set the handler
    Game.Input.RegKey(Bnew, ord('N'), [], keystart);
  end;

  bexit := Game.GamePix.Addbtn(170, 350, ResMan.GraphicN[giExit]);
  with bexit do
  begin
    GrafDefinesSize;
    ImgObj.onMouse := Gquit;
    Game.Input.RegKey(Bexit, VK_ESCAPE, [], preclose);
  end;

  bresume := Game.GamePix.Addbtn(220, 350, ResMan.GraphicN[giResume]);
  with bresume do
  begin
    ImgObj.onMouse := GresumeGame;
    GrafDefinesSize;
    //ImgObj.drawdisabled := true; // disabled until game is "paused"
    bresume.ImgObj.DrawDisabled := not Game.MapLoaded;
  end;

  Ltitle := Game.GamePix.Addlst(30, 180); // Add aethra title
  with Ltitle do
  begin
    Font := ResMan.FontN[fiTitle];
    FontStyle := [fsBold];
    borderofs := 25;
    //DrawLayerIfListEmpty := True;
    //LoadPngtoBmp(Itembk, GrafPath + 'paper.png');
    //LoadPngtoBmp(layer, GrafPath + 'inFormation.Bmp');
    AddRow(Apptitle + ' ' + Appver).ImgObj.OnTick := Titleglow;
    //gipWidth := 30;
    //gipHeight := 300;
    //AddMultiLineText('chto ty smotrish na menya razdevaisya ya tvoya');
    //Items[0].Img.LoadFromFile(GrafPath + '1.Bmp');
  end;

  //  Angel := TGameIntfAnim.Create(game.GamePix.IntfPartsColl);
  //  with Angel do
  //  begin
  //    xCord := 80;
  //    yCord := 80;
  //    ImgObj.ImgLst := resman.GraphicN[gitergrass].ImgLst;
  //    GrafDefinesSize;
  //    ImgObj.Mover := TBouncer.Create(TNodeMaker.MakeBounce(0, 0, ClWd, ClHg,
  //      xCord, ycord, gipWidth, gipHeight, 10, 5));
  //  end;

  PostMake;
end;

procedure TMainForm.TitleGlow(Sender: TObject);
const
  dif = 10;
var
  r, g, b: Byte;
begin
  r := GetRValue(Ltitle.FontCol);
  g := GetGValue(Ltitle.FontCol);
  b := GetBValue(Ltitle.FontCol);
  case Random(6) of
    0: if not (r in [255 - dif..255]) then
        inc(r, dif);
    1: if not (r in [0..dif]) then
        Dec(r, dif);
    2: if not (g in [255 - dif..255]) then
        inc(g, dif);
    3: if not (g in [0..dif]) then
        Dec(g, dif);
    4: if not (b in [255 - dif..255]) then
        inc(b, dif);
    5: if not (b in [0..dif]) then
        Dec(b, dif);
  end;
  Ltitle.FontCol := RGB(r, g, b);
end;

//------------------------------------------------------------------------------

procedure TMainForm.MakeMapForm;
var
  aBmp: TBmp;
  ClWd, ClHg: Integer;
begin
  PreMake;
  FormState := fsMap;
  aBmp := ResMan.GraphicN[giMapform].Bmp;
  ClientHeight := Min(aBmp.Height, screen.DeskTopHeight);
  ClientWidth := Min(aBmp.Width, screen.DeskTopWidth);
  clwd := ClientWidth;
  clhg := ClientHeight;
  Game.GamePix.Reset(ClHg, ClWd);

  bkg := Game.GamePix.Addbkgd(0, 0, ClHg, ClWd, aBmp, jmNone,
    TGameIntfBkgdSimple) as TGameIntfBkgdSimple;

  Bstart := Game.GamePix.Addbtn(480, 360, ResMan.GraphicN[giStart]);
  with Bstart do
  begin
    GrafDefinesSize;
    ImgObj.onMouse := BstartClick;
    Game.Input.RegKey(Bstart, VK_SPACE, [], keybegin);
  end;

  bback := Game.GamePix.Addbtn(13, 675, ResMan.GraphicN[giExit]);
  with bback do
  begin
    GrafDefinesSize;
    ImgObj.onMouse := BbackClick;
    Game.Input.RegKey(Bback, VK_ESCAPE, [], keyback);
  end;

  LCMaps := Game.GamePix.Addlst(90, 20);
  with LCMaps do
  begin
    Font := ResMan.FontN[fiUsual];
    SelCol := clTeal; // Color for Selected Items in list
    Selectable := True; // Set the list to be Selectable
    borderofs := 10;
    // Items are fitted in list with inside borders (Rectangular)
    interval := 5; // interval between Items

    DrawWideItemBg := True; // fill Item background to max size available
    //DrawLayerIfListEmpty := True;
    ItemBg := ResMan.GraphicN[giInfo].Bmp;
    //LoadItembg(GrafPath + 'inFormation.Bmp');
    //layer.LoadFromFile(GrafPath + 'inFormation.Bmp');
    //AddRow(Apptitle + ' ' + Appver );
    gipWidth := 200; // Set the Width for list
    //gipHeight := 300;
    //AddMultiLineText('chto ty smotrish na menya razdevaisya ya tvoya');
    Game.Input.RegKey(LCMaps, VK_DOWN, [], ListKeyDown);
    Game.Input.RegKey(LCMaps, VK_UP, [], ListKeyUp);
  end;

  LMapinfo := Game.GamePix.Addlst(350, 15);
  with LMapinfo do
  begin
    FontFace := 'tahoma';
    FontSize := 10;
    //font.Style := [fsbold];
    fontCol := clSilver;
    //SelCol := clred;
    //Selectable := True;
    borderofs := 25;
    //DrawLayerIfListEmpty := True;
    //layer.LoadFromFile(GrafPath + 'inFormation.Bmp');
    //AddRow(Apptitle + ' ' + Appver );
    gipWidth := 200;
    gipHeight := 100;
    AddMultiLineText(Game.MapMgr.Mapar[LCMaps.curSel].Descr);
    // Add Text broken to lines
  end;

  PostMake;

end;

procedure TMainForm.MakeForm(Mapind: Word);
var
  wd, hg: Word;
  Bmp: TBmp;
  right: Word;
  ClWd, ClHg: Integer;
begin
  PreMake;
  FormState := fsGame;
  WindowState := wsMaximized;
  clwd := ClientWidth;
  clhg := ClientHeight;

  Canvas.StretchDraw(BoundsRect, ResMan.GraphicN[giLoadScr].Bmp);

  Game.GamePix.Reset(0, 0);
  Game.GamePix.Reset(ClHg, Clwd);

  Bmp := resman.GraphicN[gicorner].Bmp;
  wd := Bmp.Width; //
  hg := Bmp.Height; // assume gicorner and giSide are of same sizes

  Bmp := resman.GraphicN[giGuipane].Bmp;
  right := ClWd - Trunc(Bmp.Width * (ClHg - 2 * hg) / Bmp.Height) - 1;
  Game.GamePix.AddBkgd(hg, right, ClHg - hg * 2, ClWd - right, Bmp, jmNone,
    TGameIntfStretchedBkgd);
  Flst := Game.GamePix.AddLst(hg + 20, right + 20);
  with Flst do
  begin
    Font := resman.FontN[fiDlgBtn];
    FontSize := 20;
    gipWidth := 150;
    gipHeight := 150;
    DrawWideItemBg := True;
  end;

  Bmp := resman.GraphicN[gicorner].Bmp;
  Game.GamePix.AddBkgd(0, 0, hg, wd, Bmp, jmNone, TGameIntfFlipedBkgd);
  Game.GamePix.AddBkgd(ClHg - hg, 0, hg, wd, Bmp, jmHorz, TGameIntfFlipedBkgd);
  Game.GamePix.AddBkgd(0, right - wd, hg, wd, Bmp, jmVert, TGameIntfFlipedBkgd);
  Game.GamePix.AddBkgd(ClHg - hg, right - wd, hg, wd, Bmp, jmBoth,
    TGameIntfFlipedBkgd);

  Bmp := resman.GraphicN[giSide].Bmp;
  Game.GamePix.AddBkgd(hg, 0, ClHg - hg * 2, wd, Bmp, jmVert,
    TGameIntfPavedBkgd);
  Game.GamePix.AddBkgd(ClHg - hg, wd, hg, right - wd * 2, Bmp, jmHorz,
    TGameIntfPavedBkgd);
  Game.GamePix.AddBkgd(0, wd, hg, right - wd * 2, Bmp, jmHorz,
    TGameIntfPavedBkgd);
  Game.GamePix.AddBkgd(hg, right - wd, ClHg - hg * 2, wd, Bmp, jmVert,
    TGameIntfPavedBkgd);

  Angel := TGameIntfAnim.Create(Game.GamePix.IntfPartsColl);
  with Angel do
  begin
    xCord := wd;
    yCord := hg;
    ImgObj.ImgLst := resman.GraphicN[giAngel].ImgLst;
    GrafDefinesSize;
    ImgObj.Mover := TBouncer.Create(TNodeMaker.MakeBounce(wd, hg, right - wd,
      ClHg - hg, xCord, yCord, gipWidth, gipHeight, 0, 0));
    Game.Input.RegKey(Angel, VK_Delete, [], AngelLeft);
    Game.Input.RegKey(Angel, VK_NEXT, [], AngelRight);
    Game.Input.RegKey(Angel, VK_Home, [], AngelUp);
    Game.Input.RegKey(Angel, VK_END, [], AngelDown);

  end;

  Game.AddField(hg, wd, ClHg - hg * 2, right - wd * 2);
  Game.MapLoad(Mapind);
  Game.Field.SetView(2, 2);
  Game.Field.OnCellChanged := fieldcellchanged;
  Flst.AddRow('1');
  Flst.AddRow('1');
  Flst.AddRow('1');
  Game.Input.RegKey(Game.Field, VK_ESCAPE, [], preleave);

  Game.procRedraw := Redraw;

  PostMake;
end;

procedure TMainForm.FormPaint(Sender: TObject);
begin
  Game.Render();
end;

//------------------------------------------------------------------------------

procedure TMainForm.FormMouseMove(Sender: TObject; Shift: TShiftState; x,
  y: Integer);
begin
  Game.GamePix.MouseMove(y, x, shift);
end;

procedure TMainForm.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; x, y: Integer);
begin
  Game.GamePix.MouseDown(y, x, shift);
end;

procedure TMainForm.FormMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; x, y: Integer);
begin
  Game.GamePix.MouseUp(y, x, shift);
end;

procedure TMainForm.FormMouseWheel(Sender: TObject; Shift: TShiftState;
  WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
begin
  if FormState <> fsGame then
    Exit;
  if WheelDelta > 0 then
    Game.Field.Scroll(drUp)
  else
    Game.Field.Scroll(drDown);
  Handled := True;
end;

procedure TMainForm.FieldCellChanged(Sender: TObject);
begin
  with Game.Field do
  begin
    Flst.ImgObj.Lock;
    Flst.Items[0].Text := Format('X = %d Y = %d', [CurCell.xCord, CurCell.yCord]);
    Flst.Items[1].text := Format('vr= %d vc= %d', [VisRow, VisCol]);
    Flst.ImgObj.UnLock;
    Flst.Items[2].Text := Format('xs= %d ys= %d', [ImgObj.xShift, ImgObj.yShift]);
  end;
end;

procedure TMainForm.frommenuleaverequest(dr: NdlgResult);
begin
  dlg := nil; // just Clear
  FormState := fsGame;
  if dr = drYes then
    LeavetoMenu;
end;

procedure TMainForm.SetDlg(const Value: Tsimpledlg);
begin
  if (FDlg <> nil) and (Value <> nil) then // refactor dialogues with key input
    FDlg.Free;
  FDlg := Value;
end;

procedure TMainForm.DoQuit;
begin
  //DestroyGame;
  Application.Terminate;
end;

procedure TMainForm.LeavetoMenu;
begin
  Makemenu;
  //  MenuForm.show;
  //  mainForm.Enabled := false;
  //  MainForm.Visible := False;
end;

procedure TMainForm.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
const
  keytodir: array[vk_left..vk_down] of Ndirection = (drLeft, drUp, drRight,
    drDown);
begin
  case FormState of
    fsGame:
      case Key of
        vk_left..vk_down:
          Game.Field.{imgobj.}Scroll(keytodir[key]);
      end;
  end;
  if Assigned(Dlg) then
    Dlg.KeyPush(key)
  else
    Game.Input.KeyPress(Key, Shift);
end;

procedure TMainForm.PreLeave(Sender: TObject);
begin
  dlg := Game.Createdlg(tyesnodlg, lsLeavetoMenu, frommenuleaverequest);
end;

procedure TMainForm.FormGameTimer(Sender: TObject);
begin
  //  GBgui.Caption := IntToStr(game.timertick);
end;

procedure TMainForm.fromquitrequest(dr: NdlgResult);
begin
  dlg := nil; // just Clear to be sure
  FormState := fsmenu;
  if dr = dryes then
    DoQuit(nil);
end;

procedure TMainForm.preclose;
begin
  // ask user to quit or not
  dlg := Game.Createdlg(tyesnodlg, lsleaveGame, fromquitrequest);
end;

procedure TMainForm.FormDestroy(Sender: TObject);
begin
  DestroyGame; // the only place to destroy game
end;

procedure TMainForm.fromrestartrequest(dr: NdlgResult);
begin
  dlg := nil; // just Clear
  if dr = drYes then
    start;
end;

procedure TMainForm.start;
var
  i: Integer;
begin
  Game.MapLoaded := False;
  FormState := fsMap;
  Game.GamePix.Reset(0, 0); // Clear old Pixeng data
  MakeMapForm;
  Game.TimerEnabled := False;
  lcMaps.Clear;
  if Game.MapMgr.Mapqnt <> 0 then
    for i := 0 to Game.MapMgr.Mapqnt - 1 do // show all Loaded Maps in list
      LCMaps.AddRow(Game.MapMgr.Mapar[i].Name).space := 10;
  LCMaps.OnSelChange := LCMapsChanged; // the OnSelect handler
  Game.TimerEnabled := True;
end;

procedure TMainForm.LoadResources;
begin
  Loadcursors();
  ResMan.lang.Loadlang(cfgPath + langIni);
  ResMan.LoadGraphics(cfgPath + GrafIni);
  ResMan.Loadfonts(cfgPath + fontIni);
  Screen.Cursor := crusual;

  //other res Loadings
end;

procedure TMainForm.SetDiRectories;
begin
  AppPath := extractFilePath(Application.exeName);
  GrafPath := AppPath + 'Graf\';
  cfgPath := AppPath + 'config\';
  DefsPath := GrafPath + 'Defs\';
end;

procedure TMainForm.keystart(Sender: TObject);
begin
  GnewGame(Sender, mbLeft, [], 0, 0);
end;

procedure TMainForm.keyback(Sender: TObject);
begin
  BbackClick(Sender, mbLeft, [], 0, 0);
end;

procedure TMainForm.Gquit(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; x, y: Integer);
begin
  preclose(nil);
end;

procedure TMainForm.AngelDown;
begin
  Angel.ImgObj.Mover.Vals[mpYspeed] := Min(Angel.ImgObj.Mover.Vals[mpYspeed] + 5, 20);
end;

procedure TMainForm.AngelLeft;
begin
  Angel.ImgObj.Mover.Vals[mpXspeed] := Max(Angel.ImgObj.Mover.Vals[mpXspeed] - 5, -20);
end;

procedure TMainForm.AngelRight;
begin
  Angel.ImgObj.Mover.Vals[mpXspeed] := Min(Angel.ImgObj.Mover.Vals[mpXspeed] + 5, 20);
end;

procedure TMainForm.AngelUp;
begin
  Angel.ImgObj.Mover.Vals[mpYspeed] := Max(Angel.ImgObj.Mover.Vals[mpYspeed] - 5, -20);
end;

procedure TMainForm.keyBegin(Sender: TObject);
begin
  BstartClick(Sender, mbLeft, [], 0, 0);
end;

procedure TMainForm.PostMake;
begin
  DC := GetDC(MainForm.Handle);
  Game.Init(DC, ClientHeight, ClientWidth);
  Game.GamePix.Remap;
  Game.TimerEnabled := True;
  if FF and (FormState = fsMenu) then
  begin
    Sound.StopMusic;
    Sound.PlayMusic(mcMenu);
    FF := False;
  end;
  if (FormState = fsGame) then
  begin
    Sound.StopMusic;
    Sound.PlayMusic(mcGame);
    FF := True;
  end;
end;

procedure TMainForm.PreMake;
begin
  Game.TimerEnabled := False;
  Game.Input.Clear;
  Game.timerevent := nil;
  Game.GamePix.Reset(0, 0);
  WindowState := wsNormal;
  Position := poScreenCenter;
  ReleaseDC(MainForm.Handle, DC);
  DeleteDC(DC);
end;

end.

